﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Text;
using System.Windows.Forms;
using DevExpress.XtraBars;
using CTEM.Models;
using CTEM.Controllers.BUS;
using DevExpress.XtraGrid;
using DevExpress.XtraGrid.Views.Base;
using CTEM.Controllers.Global;
using DevExpress.XtraEditors.DXErrorProvider;
using DevExpress.XtraEditors;
using CTEM.Controllers.Global;
using DevExpress.XtraEditors.Controls;
using DevExpress.Utils;
using System.Globalization;
using DevExpress.XtraGrid.Views.Grid;

namespace CTEM.ModuleForms.ManageConstruction
{
    public partial class SubcontractorManagement : DevExpress.XtraBars.Ribbon.RibbonForm
    {
        private readonly ConstructionBUS _consBUS = new ConstructionBUS();
        private List<CS_SubcontractorDTO> _listSubcons = new List<CS_SubcontractorDTO>();
        private readonly List<CS_SubcontractorDTO> _listHistory = new List<CS_SubcontractorDTO>();
        private bool _isNew;
        private bool _isAllowEdit;
        public SubcontractorManagement()
        {
            InitializeComponent();
        }

        private void SubcontractorManagement_Load(object sender, EventArgs e)
        {
            Global.InitLayoutGridView(gridViewSubcontractor);
            _isAllowEdit = true;
            AllowEditorNot();
            SetItemShortCut();
            LoadRepositoryItems();
            LoadActiveSubcontractor();
        }

        private void SetItemShortCut()
        {
            barButtonItemDelete.ItemShortcut = new BarShortcut((Keys.Control | Keys.D));
            barButtonItemAllowEdit.ItemShortcut = new BarShortcut((Keys.Control | Keys.E));
            barButtonItemUndo.ItemShortcut = new BarShortcut((Keys.Control | Keys.Z));
            barButtonItemRedo.ItemShortcut = new BarShortcut((Keys.Control | Keys.Y));
            barButtonItemRefresh.ItemShortcut = new BarShortcut((Keys.F5));
        }

        private void barButtonItemLoadAll_ItemClick(object sender, ItemClickEventArgs e)
        {
            LoadRepositoryItems();
            LoadAllSubcontractor();
        }

        private void barButtonItemRefresh_ItemClick(object sender, ItemClickEventArgs e)
        {
            LoadRepositoryItems();
            LoadActiveSubcontractor();
        }

        private void barButtonItemDelete_ItemClick(object sender, ItemClickEventArgs e)
        {
            DeleteSubcontractor();
        }

        private void barButtonItemDisable_ItemClick(object sender, ItemClickEventArgs e)
        {
            DisableSubcontractor();
        }

        private void barButtonItemUndo_ItemClick(object sender, ItemClickEventArgs e)
        {
            Undo();
        }

        private void barButtonItemRedo_ItemClick(object sender, ItemClickEventArgs e)
        {
            Redo();
        }

        /// <summary>
        /// Allow User can edit or not
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void barButtonItemAllowEdit_ItemClick(object sender, ItemClickEventArgs e)
        {
            AllowEditorNot();
        }

        /// <summary>
        /// Always allow User add new Subcontractor when allow edit or disable edit
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void gridViewSubcontractor_FocusedRowChanged(object sender, FocusedRowChangedEventArgs e)
        {
            if (e.FocusedRowHandle == GridControl.NewItemRowHandle)
            {
                gridViewSubcontractor.OptionsBehavior.Editable = true;
            }
            else
            {
                gridViewSubcontractor.OptionsBehavior.Editable = _isAllowEdit;
            }
        }

        /// <summary>
        /// Set isNew to make sure User want to create new Subcontractor
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void gridViewSubcontractor_InitNewRow(object sender, DevExpress.XtraGrid.Views.Grid.InitNewRowEventArgs e)
        {
            _isNew = true;
        }

        /// <summary>
        /// Make ExceptionMode is NoAction that's to custom control action when exception thew
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void gridViewSubcontractor_InvalidRowException(object sender, InvalidRowExceptionEventArgs e)
        {
            e.ExceptionMode = ExceptionMode.NoAction;
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void gridViewSubcontractor_InvalidValueException(object sender, InvalidValueExceptionEventArgs e)
        {
            e.ErrorText = Constants.INVALIDATE_VALUE;
            e.ExceptionMode = ExceptionMode.DisplayError;
        }

        /// <summary>
        /// Add new Subcontractor by validate new row item
        /// </summary>
        /// <param name="sender">Column View</param>
        /// <param name="e">ValidateRow Event Argurements</param>
        private void gridViewSubcontractor_ValidateRow(object sender, ValidateRowEventArgs e)
        {
            if (_isNew)
            {
                ColumnView view = sender as ColumnView;
                CS_SubcontractorDTO subconDTO = e.Row as CS_SubcontractorDTO;
                string errorMessage;
                string fieldName;
                if (_consBUS.ValidateSubcontractor(subconDTO, out errorMessage, out fieldName))
                {
                    long consID = _consBUS.CreateSubcontractor(subconDTO);
                    if (consID == 0)
                    {
                        alertControlMain.Show(this, Constants.ALERT_ERROR, Constants.CREATE_FAIL);
                    }
                    else
                    {
                        alertControlMain.Show(this, Constants.CONFIRM, String.Format("Bạn Đã Tạo Mới Nhà Thầu {0} Thành Công!", subconDTO.SubcontractorName));
                        RemoveRedoHistory();
                        subconDTO.SubcontractorID = consID;
                        subconDTO.History = HistoryLevel.ADD;
                        _listHistory.Add(subconDTO);
                    }
                    _isNew = false;
                    LoadActiveSubcontractor();
                }
                else
                {
                    e.Valid = false;
                    view.ClearColumnErrors();
                    view.SetColumnError(view.Columns[fieldName], errorMessage, ErrorType.Warning);
                    DialogResult result = XtraMessageBox.Show(errorMessage + "\nBạn có muốn nhập lại thông tin", Constants.CONFIRM, MessageBoxButtons.YesNo, MessageBoxIcon.Question);
                    if (result == DialogResult.No)
                    {
                        _isNew = false;
                        e.Valid = true;
                        LoadActiveSubcontractor();
                    }
                    else
                    {
                        view.FocusedColumn = view.Columns[fieldName];
                    }
                }
            }
            else
            {
                LoadActiveSubcontractor();
            }
        }

        /// <summary>
        /// Using to edit a Subcontractor
        /// </summary>
        /// <param name="sender">ColumhView</param>
        /// <param name="e">CellValue changed event argurements</param>
        private void gridViewSubcontractor_CellValueChanged(object sender, CellValueChangedEventArgs e)
        {
            if (!_isNew)
            {
                ColumnView view = sender as ColumnView;
                int currentRow = e.RowHandle;
                CS_SubcontractorDTO consDTO = gridViewSubcontractor.GetRow(currentRow) as CS_SubcontractorDTO;
                CS_SubcontractorDTO backupCons = _consBUS.GetSubcontractorByID(consDTO.SubcontractorID);
                string errorMessage;
                string fieldName;
                if (_consBUS.ValidateSubcontractor(consDTO, out errorMessage, out fieldName))
                {
                    bool success = _consBUS.UpdateSubcontractor(consDTO);
                    if (!success)
                    {
                        alertControlMain.Show(this, Constants.ALERT_ERROR, Constants.UPDATE_FAIL);
                    }
                    else
                    {
                        alertControlMain.Show(this, Constants.CONFIRM, String.Format("Bạn Đã Cập Nhật Thông Tin Nhà Thầu {0} Thành Công!", consDTO.SubcontractorName));
                        RemoveRedoHistory();
                        backupCons.History = HistoryLevel.EDIT;
                        _listHistory.Add(backupCons);
                    }
                    _isNew = false;
                    LoadActiveSubcontractor();
                }
                else
                {
                    view.ClearColumnErrors();
                    view.SetColumnError(view.Columns[fieldName], errorMessage, ErrorType.Warning);
                    DialogResult result = XtraMessageBox.Show(errorMessage + "\nBạn có muốn nhập lại thông tin", Constants.CONFIRM, MessageBoxButtons.YesNo, MessageBoxIcon.Question);

                    if (result == DialogResult.No)
                    {
                        LoadActiveSubcontractor();
                    }
                    else
                    {
                        view.FocusedColumn = view.Columns[fieldName];
                        return;
                    }
                }
            }
        }

        /// <summary>
        /// Allow User Edit Data
        /// </summary>
        private void AllowEditorNot()
        {
            if (_isAllowEdit)
            {
                alertControlMain.Show(this, Constants.CONFIRM, Constants.DISABLE_EIT_MESSAGE);
                _isAllowEdit = false;
                gridViewSubcontractor.OptionsBehavior.Editable = false;
                barButtonItemAllowEdit.Caption = Constants.ALLOW_EIT;
            }
            else
            {
                DialogResult result = XtraMessageBox.Show(Constants.ALLOW_EIT_MESSAGE, Constants.CONFIRM, MessageBoxButtons.YesNo, MessageBoxIcon.Question);
                if (result == DialogResult.Yes)
                {
                    _isAllowEdit = true;
                    gridViewSubcontractor.OptionsBehavior.Editable = true;
                    barButtonItemAllowEdit.Caption = Constants.DISABLE_EIT;
                }
            }
        }

        /// <summary>
        /// Load Data for Reporsity Items
        /// </summary>
        private void LoadRepositoryItems()
        {
            gridViewSubcontractor.NewItemRowText = "Click Vào Đây Để Tạo Mới Nhà Thầu!";
        }

        /// <summary>
        /// Load active Subcontractors
        /// </summary>
        private void LoadActiveSubcontractor()
        {
            LoadSubcontractor(true);
        }

        /// <summary>
        /// Load both active and inactive Subcontractors
        /// </summary>
        private void LoadAllSubcontractor()
        {
            LoadSubcontractor(false);
        }

        /// <summary>
        /// Function is called to load Subcontractors
        /// </summary>
        /// <param name="isactive">Load all Subcontractor or just active Subcontractor</param>
        private void LoadSubcontractor(bool isactive)
        {
            _listSubcons = _consBUS.LoadSubcontractor(isactive);
            cSSubcontractorDTOBindingSource.DataSource = _listSubcons;
        }

        /// <summary>
        /// Delete Subcontractor Forever
        /// </summary>
        private void DeleteSubcontractor()
        {
            int[] numOfSelectedRows = gridViewSubcontractor.GetSelectedRows();
            if (numOfSelectedRows.Length > 0)
            {
                CS_SubcontractorDTO subconDTO = gridViewSubcontractor.GetRow(numOfSelectedRows[0]) as CS_SubcontractorDTO;
                DialogResult result = XtraMessageBox.Show(String.Format("Nếu Nhà Thầu Phụ {0} Thì Toàn Bộ Dữ Liệu Liên Quan Sẽ Đều Bị Xóa Bỏ!\nBạn Có Chắc Muốn Xóa Vĩnh Viễn Nhà Thầu Này Không?", subconDTO.SubcontractorName), Constants.ALERT, MessageBoxButtons.YesNo, MessageBoxIcon.Warning);
                if (result == DialogResult.Yes)
                {
                    CS_SubcontractorDTO backupCons = _consBUS.GetSubcontractorByID(subconDTO.SubcontractorID);
                    subconDTO.IsDelete = true;
                    bool success = _consBUS.UpdateSubcontractor(subconDTO);
                    if (!success)
                    {
                        alertControlMain.Show(this, Constants.ALERT_ERROR, String.Format("Không Thể Xóa Nhà Thầu Phụ {0}", subconDTO.SubcontractorName));
                    }
                    else
                    {
                        alertControlMain.Show(this, Constants.CONFIRM, String.Format("Bạn Đã Xóa Nhà Thầu {0} Thành Công", subconDTO.SubcontractorName));
                        RemoveRedoHistory();
                        backupCons.History = HistoryLevel.EDIT;
                        _listHistory.Add(backupCons);
                    }
                }
            }
            LoadActiveSubcontractor();
        }

        /// <summary>
        /// Disable selected Subcontractor to inactive it
        /// </summary>
        private void DisableSubcontractor()
        {
            int[] numOfSelectedRows = gridViewSubcontractor.GetSelectedRows();
            if (numOfSelectedRows.Length > 0)
            {
                CS_SubcontractorDTO consDTO = gridViewSubcontractor.GetRow(numOfSelectedRows[0]) as CS_SubcontractorDTO;
                DialogResult result = XtraMessageBox.Show(String.Format("Vô Hiệu Hóa Nhà Thầu {0} Thì Chương Trình Sẽ Vô Hiệu Hóa Tất Cả Dữ Liệu Liên Quan Đến Nó!\nBạn Có Chắc Muốn Tạm Ngưng Nhà Thầu Này Không?", consDTO.SubcontractorName), Constants.ALERT, MessageBoxButtons.YesNo, MessageBoxIcon.Warning);
                if (result == DialogResult.Yes)
                {
                    CS_SubcontractorDTO backupCons = consDTO;
                    consDTO.IsActive = false;
                    bool success = _consBUS.UpdateSubcontractor(consDTO);
                    if (!success)
                    {
                        alertControlMain.Show(this, Constants.ALERT_ERROR, String.Format("Không Thể Vô Hiệu Hóa Nhà Thầu {0}", consDTO.SubcontractorName));
                    }
                    else
                    {
                        alertControlMain.Show(this, Constants.CONFIRM, String.Format("Vô Hiệu Hóa Nhà Thầu {0} Thành Công\n Bạn Có Thể Khôi Phục Bằng Cách Vào Menu Edit/Load All Tích Vào Trường Hoạt Động Của Nhà Thầu Đó", consDTO.SubcontractorName));
                        RemoveRedoHistory();
                        backupCons.History = HistoryLevel.EDIT;
                        _listHistory.Add(backupCons);
                    }
                }
            }
            LoadActiveSubcontractor();
        }

        /// <summary>
        /// After undo, item will change status to waiting for redo.
        /// But after new action work, all items wating for redo must be remove
        /// </summary>
        private void RemoveRedoHistory()
        {
            for (int i = 0; i < _listHistory.Count; i++)
            {
                var cons = _listHistory[i];
                if (cons.History.ToString().Contains(Constants.UNDO))
                {
                    _listHistory.Remove(cons);
                    i--;
                }
            }
        }

        /// <summary>
        /// Undo user action
        /// </summary>
        private void Undo()
        {
            int numHistoryItems = _listHistory.Count;
            for (int i = numHistoryItems; i > 0; i--)
            {
                var undoItem = _listHistory[i - 1];
                switch (undoItem.History)
                {
                    case HistoryLevel.ADD:
                        _consBUS.DeleteSubcontractor(undoItem.SubcontractorID);
                        _listHistory[i - 1].History = HistoryLevel.UNDO_ADD;
                        LoadActiveSubcontractor();
                        return;
                    case HistoryLevel.EDIT:
                        _listHistory[i - 1] = _consBUS.GetSubcontractorByID(undoItem.SubcontractorID);
                        _listHistory[i - 1].History = HistoryLevel.UNDO_EDIT;
                        _consBUS.UpdateSubcontractor(undoItem);
                        LoadActiveSubcontractor();
                        return;
                    case HistoryLevel.DELETE:
                        long oldConsID = _listHistory[i - 1].SubcontractorID;
                        long newConsID = _consBUS.CreateSubcontractor(undoItem);
                        if (newConsID != 0)
                        {
                            foreach (var item in _listHistory)
                            {
                                if (item.SubcontractorID == oldConsID)
                                {
                                    item.SubcontractorID = newConsID;
                                }
                            }
                            _listHistory[i - 1].History = HistoryLevel.UNDO_DELETE;
                        }
                        LoadActiveSubcontractor();
                        return;
                    case HistoryLevel.UNDO_ADD:
                        break;
                    case HistoryLevel.UNDO_EDIT:
                        break;
                    case HistoryLevel.UNDO_DELETE:
                        break;
                }
            }
        }

        /// <summary>
        /// Redo user action
        /// </summary>
        private void Redo()
        {
            int numHistoryItems = _listHistory.Count;
            for (int i = 0; i < numHistoryItems; i++)
            {
                var redoItem = _listHistory[i];
                switch (redoItem.History)
                {
                    case HistoryLevel.ADD:
                        break;
                    case HistoryLevel.EDIT:
                        break;
                    case HistoryLevel.DELETE:
                        break; ;
                    case HistoryLevel.UNDO_ADD:
                        long oldConsID = _listHistory[i].SubcontractorID;
                        long newConsID = _consBUS.CreateSubcontractor(redoItem);
                        if (newConsID != 0)
                        {
                            foreach (var item in _listHistory)
                            {
                                if (item.SubcontractorID == oldConsID)
                                {
                                    item.SubcontractorID = newConsID;
                                }
                            }
                            _listHistory[i].History = HistoryLevel.ADD;
                        }
                        LoadActiveSubcontractor();
                        return;
                    case HistoryLevel.UNDO_EDIT:
                        _listHistory[i] = _consBUS.GetSubcontractorByID(redoItem.SubcontractorID);
                        _listHistory[i].History = HistoryLevel.EDIT;
                        _consBUS.UpdateSubcontractor(redoItem);
                        LoadActiveSubcontractor();
                        return;
                    case HistoryLevel.UNDO_DELETE:
                        _consBUS.DeleteSubcontractor(redoItem.SubcontractorID);
                        _listHistory[i].History = HistoryLevel.DELETE;
                        LoadActiveSubcontractor();
                        return;
                }
            }
        }
    }
}